package main

import (
	"bytes"
	"crypto/sha256"
	"encoding/gob"
	"encoding/hex"
	"fmt"
	"log"
)

const subsidy=10	//奖励，矿工挖矿给予的奖励

//输入
type TXInput struct {
	Txid []byte		//Txid存储了交易的id
	Vout int		//Vout则保存该交易中一个output索引
	ScriptSig string	//ScriptSig仅只是保存了一个任意用户定义的钱包
}

// 交易，编号，输入，输出
type Transaction struct {
	ID []byte
	Vin []TXInput
	Vout []TXOutput
}

//交叉交易事务是否为coinbase,挖矿得来的奖励币
func (input *TXInput)CanUnlockOutPutWith(unlockingData string) bool {
	return input.ScriptSig==unlockingData
}

// 检查交易事务是否为coinbase
func (tx *Transaction)IsCoinBase() bool {
	return len(tx.Vin) == 1 && len(tx.Vin[0].Txid) == 0 && tx.Vin[0].Vout == -1
}

//设置交易ID,从二进制数据中
func (tx *Transaction)SetID(){
	var encoded bytes.Buffer	//开辟内寸
	var hash[32] byte			//哈希数组
	enc := gob.NewEncoder(&encoded)		//解码对象
	err := enc.Encode(tx)		//解码
	if err != nil {
		log.Panic(err)
	}
	hash=sha256.Sum256(encoded.Bytes())		//计算哈希
	tx.ID=hash[:]		//设置ID
}

//输出
type TXOutput struct {
	Value int	//output保存了“币”（上面额value）
	ScriptPubkey string		//用脚本语言意味着比特币可以也作为智能合约平台
}

//是否可以解锁输出
func (out *TXOutput)CanBeUnlockedWith(unlockingData string)bool {
	return out.ScriptPubkey==unlockingData
}

//挖矿交易
func NewCoinBaseTX(to string,data string)*Transaction  {
	if data == ""{
		data=fmt.Sprintf("挖矿奖励给%s",to)
	}
	txin:=TXInput{Txid:[]byte{},Vout:-1,ScriptSig:data}	//输入奖励
	txout:=TXOutput{Value:subsidy,ScriptPubkey:to}	//输出奖励
	tx:=Transaction{ID:nil,Vin:[]TXInput{txin}, Vout:[]TXOutput{txout}}	//交易
	return &tx
}

//转账交易
func NewUTXOTransaction(from,to string,amount int,bc *BlockChain)*Transaction{
	var inputs [] TXInput	//输入
	var outputs []TXOutput	//输出
	acc,validOutputs:=bc.FindSpendableOutputs(from,amount)
	if acc<amount{
		log.Panic("交易金额不足")
	}
	for txid,outs := range validOutputs{	//循环遍历无效输出
		txID,err := hex.DecodeString(txid)
		if err!=nil{
			log.Panic(err)	//处理错误
		}
		for _,out:=range outs{
			input:=TXInput{txID,out,from}	//输入交易
			inputs=append(inputs,input)							//输出交易
		}
	}
	//交易叠加
	outputs=append(outputs,TXOutput{amount,to})
	if acc>amount{
		//记录以后的金额
		outputs=append(outputs,TXOutput{acc-amount,from})
	}
	tx:=Transaction{nil,inputs,outputs}
	tx.SetID()	//设置ID
	return &tx	//返回交易

}




